/* * $Id: 21310a71a863a4509acff70d5be98ed78533e4d0 $ * * This file is part of the iText (R) project. * Copyright (c) 1998-2016 iText Group NV * Authors: Balder Van Camp, Emiel Ackermann, et al. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License version 3 * as published by the Free Software Foundation with the addition of the * following permission added to Section 15 as permitted in Section 7(a): * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY * ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT * OF THIRD PARTY RIGHTS * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * You should have received a copy of the GNU Affero General Public License * along with this program; if not, see http://www.gnu.org/licenses or write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA, 02110-1301 USA, or download the license from the following URL: * http://itextpdf.com/terms-of-use/ * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License. * * In accordance with Section 7(b) of the GNU Affero General Public License, * a covered work must retain the producer line in every PDF that is created * or manipulated using iText. * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the iText software without * disclosing the source code of your own applications. * These activities include: offering paid services to customers as an ASP, * serving PDFs on the fly in a web application, shipping iText with a closed * source product. * * For more information, please contact iText Software Corp. at this * address: sales@itextpdf.com */ package com.itextpdf.tool.xml.pipeline.html; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import com.itextpdf.text.*; import com.itextpdf.tool.xml.CustomContext; import com.itextpdf.tool.xml.Experimental; import com.itextpdf.tool.xml.XMLWorkerFontProvider; import com.itextpdf.tool.xml.css.apply.ListStyleTypeCssApplier; import com.itextpdf.tool.xml.css.apply.MarginMemory; import com.itextpdf.tool.xml.css.apply.PageSizeContainable; import com.itextpdf.tool.xml.exceptions.NoDataException; import com.itextpdf.tool.xml.html.CssAppliers; import com.itextpdf.tool.xml.html.CssAppliersAware; import com.itextpdf.tool.xml.html.CssAppliersImpl; import com.itextpdf.tool.xml.html.Header; import com.itextpdf.tool.xml.html.Image; import com.itextpdf.tool.xml.html.TagProcessor; import com.itextpdf.tool.xml.html.TagProcessorFactory; import com.itextpdf.tool.xml.html.Tags; /** * The CustomContext object for the HtmlPipeline.<br /> * Use this to configure your {@link HtmlPipeline}. * @author redlab_b * */ public class HtmlPipelineContext implements CustomContext, Cloneable, MarginMemory, PageSizeContainable, CssAppliersAware { /** * Key for the memory, used to store bookmark nodes */ public static final String BOOKMARK_TREE = "header.autobookmark.RootNode"; /** * Key for the memory, used in Html TagProcessing */ public static final String LAST_MARGIN_BOTTOM = "lastMarginBottom"; private final LinkedList<StackKeeper> queue; private boolean acceptUnknown = true; private TagProcessorFactory tagFactory; private final List<Element> ctn = new ArrayList<Element>(); private ImageProvider imageProvider; private String resourcesRootPath; private Rectangle pageSize = PageSize.A4; private Charset charset; private List<String> roottags = Arrays.asList(new String[] { "body", "div" }); private LinkProvider linkprovider; private boolean autoBookmark = true; private final Map<String, Object> memory; private CssAppliers cssAppliers; /** * Construct a new HtmlPipelineContext object */ public HtmlPipelineContext(CssAppliers cssAppliers) { this.queue = new LinkedList<StackKeeper>(); this.memory = new HashMap<String, Object>(); this.cssAppliers = cssAppliers; if (this.cssAppliers == null) { this.cssAppliers = new CssAppliersImpl(new XMLWorkerFontProvider()); } } /** * @param tag the tag to find a TagProcessor for * @param nameSpace the namespace. * @return a TagProcessor */ protected TagProcessor resolveProcessor(final String tag, final String nameSpace) { TagProcessor tp = tagFactory.getProcessor(tag, nameSpace); if (tp instanceof CssAppliersAware) { ((CssAppliersAware) tp).setCssAppliers(this.cssAppliers); } return tp; } /** * Add a {@link StackKeeper} to the top of the stack list. * @param stackKeeper the {@link StackKeeper} */ protected void addFirst(final StackKeeper stackKeeper) { this.queue.addFirst(stackKeeper); } /** * Retrieves, but does not remove, the head (first element) of this list. * @return a StackKeeper or null if there are no elements on the stack */ protected StackKeeper peek() { if (!this.queue.isEmpty()) return this.queue.getFirst(); return null; } /** * @return the current content of elements. */ protected List<Element> currentContent() { return ctn; } /** * @return if this pipelines tag processing accept unknown tags: true. False otherwise */ public boolean acceptUnknown() { return this.acceptUnknown; } /** * @return returns true if the stack is empty */ protected boolean isEmpty() { return queue.isEmpty(); } /** * Retrieves and removes the top of the stack. * @return a StackKeeper * @throws NoStackException if there are no elements on the stack */ protected StackKeeper poll() throws NoStackException { try { return this.queue.removeFirst(); } catch (NoSuchElementException e) { throw new NoStackException(); } } /** * @return true if auto-bookmarks should be enabled. False otherwise. */ public boolean autoBookmark() { return autoBookmark; } /** * @return the memory */ public Map<String, Object> getMemory() { return memory; } /** * @return the image provider or null if there is no {@link ImageProvider}. * */ public ImageProvider getImageProvider() { return this.imageProvider; } /** * Set a {@link Charset} to use. * @param cSet the charset. * @return this <code>HtmlPipelineContext</code> */ @Experimental public HtmlPipelineContext charSet(final Charset cSet) { this.charset = cSet; return this; } /** * @return the {@link Charset} to use, or null if none configured. */ public Charset charSet() { return charset; } /** * Returns a {@link Rectangle} * @return the pagesize. */ public Rectangle getPageSize() { return this.pageSize; } /** * @return a list of tags to be taken as root-tags. This matters for * margins. By default the root-tags are <body> and * <div> */ public List<String> getRootTags() { return roottags; } /** * Returns the LinkProvider, used to prepend e.g. http://www.example.org/ to * found <a> tags that have no absolute url. * * @return the LinkProvider if any. */ public LinkProvider getLinkProvider() { return linkprovider; } /** * If no pageSize is set, the default value A4 is used. * @param pageSize the pageSize to set * @return this <code>HtmlPipelineContext</code> */ public HtmlPipelineContext setPageSize(final Rectangle pageSize) { this.pageSize = pageSize; return this; } /** * Create a clone of this HtmlPipelineContext, the clone only contains the * initial values, not the internal values. Beware, the state of the current * Context is not copied to the clone. Only the configurational important * stuff like the LinkProvider (same object), ImageProvider (new * {@link AbstractImageProvider} with same ImageRootPath) , * TagProcessorFactory (same object), acceptUnknown (primitive), charset * (Charset.forName to get a new charset), autobookmark (primitive) are * copied. */ @Override public HtmlPipelineContext clone() throws CloneNotSupportedException { CssAppliers cloneCssApliers = this.cssAppliers.clone(); HtmlPipelineContext newCtx = new HtmlPipelineContext(cloneCssApliers); if (this.imageProvider != null) { newCtx.setImageProvider(imageProvider); } if (this.resourcesRootPath != null) { newCtx.setResourcesRootPath(resourcesRootPath); } if (null != this.charset) { newCtx.charSet(Charset.forName(this.charset.name())); } newCtx.setPageSize(new Rectangle(this.pageSize)).setLinkProvider(this.linkprovider) .setRootTags(new ArrayList<String>(this.roottags)).autoBookmark(this.autoBookmark) .setTagFactory(this.tagFactory).setAcceptUnknown(this.acceptUnknown).setCssApplier(cloneCssApliers); return newCtx; } /** * Set to true to allow the HtmlPipeline to accept tags it does not find in * the given {@link TagProcessorFactory} * * @param acceptUnknown true or false * @return this <code>HtmlPipelineContext</code> */ public HtmlPipelineContext setAcceptUnknown(final boolean acceptUnknown) { this.acceptUnknown = acceptUnknown; return this; } /** * Set the {@link TagProcessorFactory} to be used. For HTML use {@link Tags#getHtmlTagProcessorFactory()} * @param tagFactory the {@link TagProcessorFactory} that should be used * @return this <code>HtmlPipelineContext</code> */ public HtmlPipelineContext setTagFactory(final TagProcessorFactory tagFactory) { this.tagFactory = tagFactory; return this; } /** * Set to true to enable the automatic creation of bookmarks on <h1> * to <h6> tags. Works in conjunction with {@link Header}. * * @param autoBookmark true or false * @return this <code>HtmlPipelineContext</code> */ public HtmlPipelineContext autoBookmark(final boolean autoBookmark) { this.autoBookmark = autoBookmark; return this; } /** * Set the root-tags, this matters for margins. By default these are set to * <body> and <div>. * * @param roottags the root tags * @return this <code>HtmlPipelineContext</code> */ public HtmlPipelineContext setRootTags(final List<String> roottags) { this.roottags = roottags; return this; } /** * An ImageProvider can be provided and works in conjunction with * {@link Image} and {@link ListStyleTypeCssApplier} for List Images. * * @param imageProvider the {@link ImageProvider} to use. * @return this <code>HtmlPipelineContext</code> */ public HtmlPipelineContext setImageProvider(final ImageProvider imageProvider) { this.imageProvider = imageProvider; return this; } /** * Set the LinkProvider to use if any. * * @param linkprovider the LinkProvider (@see * {@link HtmlPipelineContext#getLinkProvider()} * @return this <code>HtmlPipelineContext</code> */ public HtmlPipelineContext setLinkProvider(final LinkProvider linkprovider) { this.linkprovider = linkprovider; return this; } /* (non-Javadoc) * @see com.itextpdf.tool.xml.css.MarginMemory#getLastMarginBottom() */ public Float getLastMarginBottom() throws NoDataException { Map<String, Object> memory = getMemory(); Object o = memory.get(HtmlPipelineContext.LAST_MARGIN_BOTTOM); if (null == o) { throw new NoDataException(); } else { return (Float) o; } } /* (non-Javadoc) * @see com.itextpdf.tool.xml.css.MarginMemory#setLastMarginBottom(float) */ public void setLastMarginBottom(final Float lmb) { getMemory().put(HtmlPipelineContext.LAST_MARGIN_BOTTOM, lmb); } /* * (non-Javadoc) * * @see com.itextpdf.tool.xml.html.CssAppliersAware#setCssAppliers(com.itextpdf.tool.xml.html.CssAppliers) */ public void setCssAppliers(final CssAppliers cssAppliers) { this.cssAppliers = cssAppliers; } /* * (non-Javadoc) * * @see com.itextpdf.tool.xml.html.CssAppliersAware#getCssAppliers() */ public CssAppliers getCssAppliers() { return cssAppliers; } /** * Fluent variant of {@link #setCssAppliers(CssAppliers)} * * @param cssAppliers the cssAppliers * @return this */ public HtmlPipelineContext setCssApplier(final CssAppliers cssAppliers) { this.cssAppliers = cssAppliers; return this; } public String getResourcesRootPath() { return resourcesRootPath; } public void setResourcesRootPath(String resourcesRootPath) { this.resourcesRootPath = resourcesRootPath; } }